home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Files / XTND 1.3.6 / Application Examples / PascalSource / XTEFileIO.p < prev    next >
Encoding:
Text File  |  1992-03-17  |  41.8 KB  |  1,397 lines  |  [TEXT/MPS ]

  1. (************************************************************************
  2. *                                                                        *
  3. *    File:        XTEFileIO.p                                                *
  4. *                                                                        *
  5. *    Contains:    Import/Export Code for use with XTEStyleSample            *
  6. *                                                                        *
  7. *    Copyright:    © 1989-91 by Claris Corporation, all rights reserved.    *
  8. *                                                                        *
  9. *    Change History:                                                        *
  10. *                                                                        *
  11. *        11/7/89     RJS        First version                                *
  12. *        4/15/91        MJ        Pascal version                                 *
  13. *                                                                        *
  14. ************************************************************************)
  15. UNIT XTEFileIO;
  16.  
  17. INTERFACE
  18.  
  19. USES
  20.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, 
  21.     Traps, MacPrint, Packages, TextEdit,
  22.     XTNDInterface, XTNDTextTranslator, XTNDPictTranslator;
  23.  
  24. CONST
  25.     kNoText         = '';
  26.     kTabChar         = '\t';
  27.     kSpaceChar        = ' ';
  28.     kReturnChar        = '\n';
  29.     kRightBracket     = ']';
  30.     kFormulaText     = '[Formula]';
  31.     kNumberText     = '[Number]';
  32.     kCitationText     = '[Citation]';
  33.     kUnknownChar     = '[Unknown Special Char';
  34.     kUnknownFrame     = '[Unknown Frame]';
  35.     kMergeBreak     = '\r[Merge Break]\r';
  36.     kColumnBreak     = '\r[Column Break]\r';
  37.     kPageBreak         = '\r[Page Break]\r';
  38.     kSegmentBreak     = '\r[Segment Break]\r';
  39.     kSectionBreak     = '\r[Section Break]\r';
  40.     kPageNumText     = '[Page Number]';
  41.     kFootnoteText     = '[Footnote #';
  42.     kPictureText     = '[Picture #';
  43.  
  44.     kNativeTypes    = 1;
  45.  
  46.     {kMaxDocWidth is an arbitrary number used to specify the width of the TERec's
  47.     destination rectangle so that word wrap and horizontal scrolling can be
  48.     demonstrated.}
  49.     kMaxDocWidth            = 576;
  50.     
  51.     {kTextMargin is the number of pixels we leave blank at the edge of the window.}
  52.     kTextMargin                = 2;
  53.  
  54.     {kScrollBarAdjust and kScrollBarWidth are used in calculating
  55.     values for control positioning and sizing.}
  56.     kScrollbarWidth            = 16;
  57.     kScrollbarAdjust        = kScrollbarWidth - 1;
  58.  
  59.     {kScrollTweek compensates for off-by-one requirements of the scrollbars
  60.      to have borders coincide with the growbox.}
  61.     kScrollTweek            = 2;
  62.  
  63.     {kCrChar is used to match with a carriage return when calculating the
  64.     number of lines in the TextEdit record. kDelChar is used to check for
  65.     delete in keyDowns.}
  66.     kCRChar                    = 13;
  67.     kDelChar                = 8;
  68.  
  69.     {kButtonScroll is how many pixels to scroll horizontally when the button part
  70.     of the horizontal scrollbar is pressed.}
  71.     kButtonScroll            = 4;
  72.     
  73.     {kErrStrings is the resource ID for the error strings STR# resource.}
  74.     kErrStrings        = 128;
  75.     kFileMessageID    = 131;
  76.     kTextRunsDispID    = 134;    
  77.     
  78.     { The following constants are all resource IDs, corresponding to their resources }
  79.     
  80.     rMenuBar    = 128;                { application's menu bar }
  81.     rAboutAlert    = 128;                { about alert }
  82.     rDocWindow    = 128;                { application's window }
  83.     
  84.     rVScroll    = 128;                { vertical scrollbar control }
  85.     rHScroll    = 129;                { horizontal scrollbar control }
  86.  
  87.     rUserAlert        = 129;                { user error alert }
  88.  
  89.     { The following are indicies into STR# resources. }
  90.     eWrongMachine    = 1;
  91.     eSmallSize        = 2;
  92.     eNoMemory        = 3;
  93.     eNoSpaceCut        = 4;
  94.     eNoCut            = 5;
  95.     eNoCopy            = 6;
  96.     eExceedPaste    = 7;
  97.     eNoSpacePaste    = 8;
  98.     eNoWindow        = 9;
  99.     eExceedChar        = 10;
  100.     eNoPaste        = 11;
  101.     eNoXTND            = 12;
  102.     eTranslatorLoad    = 13;
  103.     eImportOpenRes    = 14;
  104.     eFilterRead        = 15;
  105.     eImportOpen        = 16;
  106.     eFilterInit        = 17;
  107.     eDeleteFailed    = 18;
  108.     eCreateFail        = 19;
  109.     eOpenFail        = 20;
  110.  
  111. { QuickDraw text styles }
  112.     kQDBold            = 1;
  113.     kQDItalic        = 2;
  114.     kQDUnderline    = 4;
  115.     kQDOutline        = 8;
  116.     kQDShadow        = 16;
  117.     
  118. TYPE
  119.     {A DocumentRecord contains the WindowRecord for one of our document windows,
  120.      as well as the TEHandle for the text we are editing. We have added fields to
  121.      hold the ControlHandles to the vertical and horizontal scrollbars and to hold
  122.      the address of the default clikLoop that gets attached to a TERec when you call
  123.      TEAutoView. Other document fields can be added to this record as needed. For
  124.      a similar example, see how the Window Manager and Dialog Manager add fields
  125.      after the GrafPort.}
  126.     DocumentRecord        = RECORD
  127.         docWindow        : WindowRecord;
  128.         docTE            : TEHandle;
  129.         docVScroll        : ControlHandle;
  130.         docHScroll        : ControlHandle;
  131.         docClik            : ProcPtr;
  132.         fileName        : Str255;
  133.         WDRefNum        : INTEGER;
  134.         myPrintRec        : THPrint;
  135.     END;
  136.     DocumentPeek        = ^DocumentRecord;
  137.  
  138. (*----------------------------- Variables -----------------------------------*)
  139. VAR
  140.     (*-------- External Variables ---------*)
  141.     gMyFileType            : ARRAY [1..kNativeTypes] OF TransDescribe;
  142.     gFilterSelected        : INTEGER;
  143.     gTheReply            : SFReply;
  144.     gInitWndSize        : Point;        (*initial window size for saved files*)
  145.     gTheActiveWindow    : WindowPtr;    (*pointer to front window*)
  146.     WATCH                : CursHandle;
  147.  
  148.     (*-------- text ---------*)
  149.     gTextH                : TEHandle;        (*handle to text in front window*)
  150.     gSelStart            : INTEGER;        (*start of initial selection range*)
  151.     gSelEnd                : INTEGER;        (*end of initial selection range*)
  152.     gIBeamHdl            : CursHandle;    (*handle to the I-beam cursor image*)
  153.  
  154.     (* The following globals are to support XTND import/export *)
  155.     gShowTextRuns        : Boolean;
  156.     gBeforeDivider        : Boolean;
  157.     gXTNDAvail            : Boolean;
  158.  
  159.     (*-------- Global Variables ---------*)
  160.     gImportPB            : ImportParmBlock;
  161.     gPictImportPB        : PictImportParmBlk;
  162.     exportPB            : ExportParmBlock;
  163.     gExportTranslator,
  164.     gImportTranslator    : TransProcPtr;
  165.     gParafmts            : ARRAY [1..9] OF Fixed;
  166.     gTabs                : tabspecArray;
  167.     gFNMarker            : PACKED ARRAY [1..10] OF Byte;
  168.     gNow                : LongInt;
  169.     gNumDocuments,
  170.     gFootnoteCount        : INTEGER;
  171.     gFNStoryCount        : INTEGER;
  172.     gPictCount            : INTEGER;
  173.     gExportTextHandle    : Handle;
  174.  
  175.     gExportTextLength    : LongInt;
  176.     gExportError        : INTEGER;
  177.     gExportRefNum        : INTEGER;
  178.     gExportTxtFace        : INTEGER;
  179.     gExportTxtSize        : INTEGER;
  180.     gExportTxtFont        : INTEGER;
  181.     gExportTxtColor        : Byte;
  182.     gExportTxtJust        : INTEGER;
  183.     Load_stored         : INTEGER;
  184.     Save_stored            : INTEGER;
  185.  
  186.  
  187. (*--------------------------- Routines in this file ----------------------------*)
  188. PROCEDURE AlertUser( error, code : INTEGER );
  189. PROCEDURE AdjustHV( isVert : BOOLEAN; control : ControlHandle; 
  190.                     docTE : TEHandle; canRedraw : BOOLEAN );
  191. PROCEDURE AdjustScrollValues( window : WindowPtr; canRedraw : BOOLEAN );
  192. PROCEDURE GetTERect( window : WindowPtr; VAR teRect : Rect);
  193. FUNCTION IsDAWindow( window : WindowPtr ) : BOOLEAN;
  194. FUNCTION IsAppWindow( window : WindowPtr ) : BOOLEAN;
  195. FUNCTION  DoCloseWindow( window : WindowPtr ) : BOOLEAN;
  196. PROCEDURE DoSave(saveAs : Boolean);
  197. PROCEDURE DoOpen;
  198. PROCEDURE DoNew;
  199.  
  200.  
  201. (* ========================================================================≠============≠============== *)
  202. IMPLEMENTATION
  203.  
  204. CONST
  205. {QUICKDRAWSTYLES = ORD(bold) + ORD(italic) + ORD(underline) + ORD(outline) + ORD(shadow); }
  206.     QUICKDRAWSTYLES = 127;
  207.  
  208.  
  209. {$S Import}
  210. FUNCTION IsDAWindow( window : WindowPtr ) : BOOLEAN;
  211. {  Check if a window belongs to a desk accessory. }
  212. BEGIN { IsDAWindow }
  213.     IF window = NIL THEN
  214.         IsDAWindow := FALSE
  215.     ELSE    { DA windows have negative windowKinds }
  216.         IsDAWindow := WindowPeek( window )^.windowKind < 0;
  217. END; { IsDAWindow }
  218.  
  219. FUNCTION IsAppWindow( window : WindowPtr ) : BOOLEAN;
  220. {  Check if a window belongs to the application. }
  221. BEGIN { IsAppWindow }
  222.     IF window = NIL THEN
  223.         IsAppWindow := FALSE
  224.     ELSE    { application windows have non-negative windowKinds }
  225.         IsAppWindow := WindowPeek( window )^.windowKind >= 0;
  226. END; { IsAppWindow }
  227.  
  228. PROCEDURE AlertUser( error, code : INTEGER );
  229. {  Display an alert that tells the user an error occurred, then exit the program }
  230. VAR
  231.     itemHit    : INTEGER;
  232.     message, tempStr: Str255;
  233.  
  234. BEGIN { AlertUser }
  235.     SetCursor(arrow);
  236.     GetIndString(message, kErrStrings, error);
  237.     IF code <> 0 THEN BEGIN
  238.         NumToString(code, tempStr);
  239.         tempStr := concat('error number ', tempStr);
  240.         END
  241.     ELSE
  242.         tempStr := '';
  243.     ParamText(message, tempStr, '', '');
  244.     itemHit := Alert( rUserAlert, NIL );
  245. END; { AlertUser }
  246.  
  247. PROCEDURE AdjustHV( isVert : BOOLEAN; control : ControlHandle; 
  248.                     docTE : TEHandle; canRedraw : BOOLEAN );
  249.                     
  250. {Calculate the new control maximum value and current value, whether it is the horizontal or
  251. vertical scrollbar. The vertical max is calculated by comparing the number of lines to the
  252. vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document
  253. width to the width of the viewRect. The current values are set by comparing the offset between
  254. the view and destination rects. If necessary and we canRedraw, have the control be re-drawn by
  255. calling ShowControl.}
  256.  
  257. {TEStyleSample-vertical max originally used line by line calculations-lineheight was a
  258. constant value so it was easy to figure out what the range should be and pin the value
  259. within range. Now we need to use max and min values in pixels rather than in nlines}
  260.  
  261. VAR
  262.     value, max             : INTEGER;
  263.     oldValue, oldMax    : INTEGER;
  264.     
  265. BEGIN { AdjustHV }
  266.     oldValue := GetCtlValue( control );
  267.     oldMax := GetCtlMax( control );
  268.     IF isVert THEN BEGIN
  269.         { new for TEStyleSample }
  270.         max := ( TEGetHeight( docTE^^.nLines, 0, docTE ) ) - 
  271.                             ( docTE^^.viewRect.bottom - docTE^^.viewRect.top );
  272.     END ELSE
  273.         max := kMaxDocWidth - (docTE^^.viewRect.right - docTE^^.viewRect.left );
  274.     
  275.     IF max < 0 THEN
  276.         max := 0;            { check for negative values }
  277.     SetCtlMax( control, max );
  278.     IF isVert THEN
  279.         value := docTE^^.viewRect.top - docTE^^.destRect.top 
  280.     ELSE
  281.         value := docTE^^.viewRect.left - docTE^^.destRect.left;
  282.     IF value < 0 THEN
  283.         value := 0
  284.     ELSE IF value > max THEN
  285.         value := max;        { pin the value to within range }
  286.     SetCtlValue( control, value );
  287.     IF canRedraw & ( ( max <> oldMax ) | ( value <> oldValue ) ) THEN
  288.         ShowControl( control );            { check to see if the control can be re-drawn }
  289. END; { AdjustHV }
  290.  
  291. PROCEDURE GetTERect( window : WindowPtr; VAR teRect : Rect);
  292. {   return a rectangle that is inset from the portRect by the size of
  293.     the scrollbars and a little extra margin. }
  294. BEGIN { GetTERect }
  295.     teRect := window^.portRect;
  296.     InsetRect( teRect, kTextMargin, kTextMargin );        { adjust for margin }
  297.     teRect.bottom := teRect.bottom - kScrollbarAdjust;    { and for the scrollbars }
  298.     teRect.right := teRect.right - kScrollbarAdjust;
  299. END; { GetTERect }
  300.  
  301. FUNCTION DoCloseWindow( window : WindowPtr ) : BOOLEAN;
  302. {    Close a window. This handles desk accessory and application windows. }
  303.  
  304. BEGIN { DoCloseWindow }
  305.     DoCloseWindow := TRUE;
  306.     IF IsDAWindow( window ) THEN
  307.         CloseDeskAcc( WindowPeek( window )^.windowKind )
  308.     ELSE IF IsAppWindow( window ) THEN BEGIN
  309.         WITH DocumentPeek( window )^ DO
  310.             IF docTE <> NIL THEN
  311.                 TEDispose( docTE );
  312.         CloseWindow( window );
  313.         DisposPtr( Ptr( window ) );
  314.         gNumDocuments := gNumDocuments - 1;
  315.     END;
  316. END; { DoCloseWindow }
  317.  
  318. PROCEDURE AdjustScrollValues( window : WindowPtr; canRedraw : BOOLEAN );
  319.  
  320. {    Simply call the common adjust routine for the vertical and horizontal scrollbars. }
  321.  
  322. BEGIN { AdjustScrollValues }
  323.     WITH DocumentPeek( window )^ DO BEGIN
  324.         AdjustHV( TRUE, docVScroll, docTE, canRedraw );
  325.         AdjustHV( FALSE, docHScroll, docTE, canRedraw );
  326.     END; { with }
  327. END; { AdjustScrollValues }
  328.  
  329. PROCEDURE AsmClikLoop; EXTERNAL;
  330. {    A reference to our assembly language routine that gets attached to the clikLoop field of our TE record. }
  331. PROCEDURE DoNew;
  332. {    Create a new document and window. }
  333.  
  334. {Minor changes from TESample--TEStylNew instead of TENew-makes certain fields in
  335. the edit record (lineHeight, txFont, and txFace) have value of -1 and alloctes new
  336. tables to hold style information}
  337.  
  338. VAR
  339.     good, ignore        : BOOLEAN;
  340.     storage                : Ptr;
  341.     window                : WindowPtr;
  342.     destRect, viewRect    : Rect;
  343.  
  344. BEGIN { DoNew }
  345.     storage := NewPtr( SIZEOF( DocumentRecord ) );
  346.     IF storage <> NIL THEN BEGIN
  347.         window := GetNewWindow( rDocWindow, storage, WindowPtr( -1 ) );
  348.         IF window <> NIL THEN BEGIN
  349.             gTheActiveWindow := window;
  350.             gNumDocuments := gNumDocuments + 1;
  351.             good := FALSE;
  352.             SetPort( window );
  353.             WITH window^, DocumentPeek( window )^ DO BEGIN
  354.                 GetTERect( window, viewRect );
  355.                 destRect := viewRect;
  356.                 destRect.right := destRect.left + kMaxDocWidth;
  357.                 docTE := TEStylNew( destRect, viewRect );
  358.                 { Use TEStylNew instead of TENew to initialize TERec correctly }
  359.                 IF docTE <> NIL THEN BEGIN
  360.                     good := TRUE;                {if TENew succeeded, we have a good document}
  361.                     TEAutoView(TRUE, docTE);
  362.                     docClik := docTE^^.clikLoop;
  363.                     docTE^^.clikLoop := @AsmClikLoop;
  364.                 END;
  365.                 IF good THEN BEGIN
  366.                     myPrintRec := THPrint(NewHandle(sizeof(TPrint)));
  367.                     IF myPrintRec <> NIL THEN BEGIN
  368.                         PrOpen; 
  369.                         PrintDefault(myPrintRec); (* load in default settings *)
  370.                         PrClose;
  371.                     END ELSE
  372.                     myPrintRec := NIL;
  373.                 END;
  374.                 IF good THEN BEGIN
  375.                     docVScroll := GetNewControl( rVScroll, window );
  376.                     good := ( docVScroll <> NIL );
  377.                 END; { if }
  378.                 IF good THEN BEGIN
  379.                     docHScroll := GetNewControl( rHScroll, window );
  380.                     good := ( docHScroll <> NIL );
  381.                 END; { if }
  382.                 IF good THEN BEGIN
  383.                     AdjustScrollValues( window, FALSE );
  384.                     ShowWindow( window ); { if the document is good, make the window visible }
  385.                 END ELSE BEGIN
  386.                     ignore := DoCloseWindow( window ); { otherwise regret we ever created it... }
  387.                     AlertUser( eNoWindow, 0 ); { and tell user }
  388.                 END { if }
  389.             END; { with }
  390.         END ELSE
  391.             DisposPtr( storage ); { get rid of the storage if it is never used }
  392.     END; { if }
  393. END; { DoNew }
  394.  
  395.  
  396. (* ------------------------------------------------------------------------+------------+-------------- *)
  397. PROCEDURE RGBFromXTND(VAR rgb: RGBColor; colorcode: INTEGER);
  398. BEGIN
  399.     CASE colorcode OF
  400.         0:    { WHITE }
  401.           BEGIN
  402.             rgb.red := 65535; rgb.green := 65535; rgb.blue := 65535
  403.           END;
  404.         1:    { BLACK }
  405.           BEGIN
  406.             rgb.red := 0; rgb.green := 0; rgb.blue := 0
  407.           END;
  408.         2:    { RED }
  409.           BEGIN
  410.             rgb.red := 65535; rgb.green := 0; rgb.blue := 0
  411.           END;
  412.         3:    { GREEN }
  413.           BEGIN
  414.             rgb.red := 0; rgb.blue := 0; rgb.green := 65535
  415.           END;
  416.         4:    { BLUE }
  417.           BEGIN
  418.             rgb.red := 0; rgb.green := 0; rgb.blue := 65535
  419.           END;
  420.         5:    { CYAN }
  421.           BEGIN
  422.             rgb.red := 0; rgb.green := 65535; rgb.blue := 65535
  423.           END;
  424.         6:    { MAGENTA }
  425.           BEGIN
  426.             rgb.red := 65535; rgb.blue := 65535; rgb.green := 0
  427.           END;
  428.         7:    { YELLOW }
  429.           BEGIN
  430.             rgb.red := 65535; rgb.green := 65535; rgb.blue := 0
  431.           END
  432.     END
  433. END;
  434.  
  435.  
  436. (* ------------------------------------------------------------------------+------------+-------------- *)
  437. FUNCTION RGBToXTND(theColor : RGBColor): INTEGER;
  438.     (* ColorMap contains the conversion from QuickDraw color to our color id *)
  439. VAR
  440.     r,g,b        : INTEGER;
  441.     colormap    : ARRAY [0..7] OF INTEGER;
  442. BEGIN
  443.  
  444.     colormap[0] := 1;
  445.     colormap[1] := 4;
  446.     colormap[2] := 3;
  447.     colormap[3] := 5;
  448.     colormap[4] := 2;
  449.     colormap[5] := 6;
  450.     colormap[6] := 7;
  451.     colormap[7] := 0;
  452.  
  453.     if BAND(theColor.red, $8000) <> 0 THEN
  454.         r :=  4
  455.     ELSE
  456.         r := 0;
  457.  
  458.     if BAND(theColor.green, $8000) <> 0 THEN
  459.         g :=  2
  460.     ELSE
  461.         g := 0;
  462.  
  463.     if BAND(theColor.blue, $8000) <> 0 THEN
  464.         b := 1
  465.     ELSE
  466.         b := 0;
  467.  
  468.     RGBToXTND := colormap[r+g+b];
  469. END;
  470.  
  471. (* ========================================================================≠============≠============== *)
  472. PROCEDURE ReadFile(pChosenOne: TransDescrPtr; theReply: SFReply);
  473. VAR
  474.     window            : WindowPtr;
  475.     dummyptr        : Ptr;
  476.     TESlop            : LONGINT;
  477.     pm                : pictMiscHdl;
  478.     importPB        : ImportParmBlock;
  479.     hfsPB            : ParamBlockRec;
  480.     te                : TEHandle;
  481.     Parafmt            : ARRAY [0..8] OF Fixed;
  482.     Tabs            : ARRAY [0..19] OF tabspec;
  483.     MinusOne        : Point;
  484.     tempRect        : Rect;
  485.     Marker            : ARRAY [0..9] OF Byte;
  486.     fnum,
  487.     resfnum, 
  488.     fserr            : INTEGER;
  489.     aPtr            : IntegerPtr;
  490.     count, textrun    : LONGINT;
  491.     newStyle        : TextStyle;
  492.     Buffer,
  493.     theNumber        : Str255;
  494.     now                : LONGINT;
  495.     dummy            : OSErr;
  496.     handleLocked    : Boolean;
  497.     tempStyle        : TEStyleHandle;
  498.     state            : SignedByte;
  499. BEGIN
  500.     window := FrontWindow;
  501.     TESlop := SIZEOF(TextStyle) + 500;
  502.     fnum := 0;
  503.     resfnum := 0;
  504.     textrun := 0;
  505.  
  506.     SetCursor( GetCursor( watchCursor )^^ );
  507.     SetWTitle(window, theReply.fName);
  508.     fserr := XTNDLoadTranslator(pChosenOne, gImportTranslator);
  509.     IF fserr <> noErr THEN
  510.       BEGIN
  511.         AlertUser(eTranslatorLoad,fserr);
  512.         EXIT(ReadFile);
  513.       END;
  514.     MinusOne.v := -1;
  515.     MinusOne.h := -1;
  516.     te := DocumentPeek(window)^.docTE;
  517.     importPB.TextBuffer        := @Buffer;
  518.     importPB.result            := noErr;
  519.     importPB.TextLength        := 0;
  520.     importPB.TxtFace            := 0;    { Plain }
  521.     importPB.TxtSize            := 0;
  522.     importPB.TxtFont            := helvetica;
  523.     importPB.TxtColor            := 0;
  524.     importPB.TxtJust            := 0;    { Left }
  525.     importPB.ParaFmts            := @Parafmt;
  526.     importPB.Tabs                := @Tabs;
  527.     importPB.NumCols            := 1;
  528.     importPB.CurrentStory        := mainStory;
  529.     importPB.MiscData            := 0;
  530.     importPB.StoryHeight        := 0;
  531.     importPB.DecimalChar        := '.';
  532.     importPB.AutoHyphenate        := TRUE;
  533.     importPB.PrintRecord        := NIL;
  534.     importPB.StartPageNum        := 1;
  535.     importPB.StartFootnoteNum    := 1;
  536.     Marker[0]                    := 0;
  537.     importPB.FootnoteText        := @Marker;
  538.     importPB.RulerShowing        := TRUE;
  539.     importPB.DoubleSided        := FALSE;
  540.     importPB.TitlePage            := FALSE;
  541.     importPB.Endnotes            := FALSE;
  542.     importPB.ShowInvisibles    := FALSE;
  543.     importPB.ShowPageGuides    := TRUE;
  544.     importPB.ShowPictures        := TRUE;
  545.     importPB.AutoFootnotes        := TRUE;
  546.     importPB.PagePoint            := MinusOne;
  547.     importPB.DatePoint            := MinusOne;
  548.     importPB.TimePoint            := MinusOne;
  549.     importPB.SmartQuotes        := TRUE;
  550.     importPB.FractCharWidths    := FALSE;
  551.     importPB.HRes                := 72;
  552.     importPB.VRes                := 72;
  553.     importPB.TheReply            := theReply;
  554.     importPB.ThisTranslator    := pChosenOne^;
  555.     IF OpenRFPerm(theReply.fName, theReply.vRefNum, fsRdPerm) = -1 THEN
  556.       BEGIN
  557.           fserr := ResError;
  558.         IF fserr <> eofErr THEN                { No resource fork found }
  559.           BEGIN
  560.             AlertUser(eFilterRead,fserr);
  561.             dummy := XTNDReleaseTranslator(pChosenOne);
  562.             EXIT(ReadFile)
  563.           END;
  564.         UseResFile(pChosenOne^.ResRefNum);        { For translators expecting to be the current resource file }
  565.       END
  566.     ELSE        { If there is a resource fork for this file, read the resources }
  567.       BEGIN
  568.         resfnum := CurResFile;
  569.         importPB.RefNum := resfnum;
  570.         importPB.Directive := ImportGetResources;
  571.         XTNDCallTranslator(@importPB, gImportTranslator);
  572.         IF importPB.result <> noErr THEN
  573.           BEGIN
  574.             AlertUser(eFilterRead,importPB.result);
  575.             CloseResFile(resfnum);
  576.             dummy := XTNDReleaseTranslator(pChosenOne);
  577.             EXIT(ReadFile)
  578.           END
  579.       END;
  580.  
  581.     { Open the file read only }
  582.     fserr := 0;
  583.     hfsPB.ioNamePtr := @theReply.fName;
  584.     hfsPB.ioVRefNum := theReply.vRefNum;
  585.     hfsPB.ioVersNum := 1;
  586.     hfsPB.ioPermssn := fsRdPerm;
  587.     hfsPB.ioMisc := Ptr(0);
  588.     fserr := PBOpen(@hfsPB, FALSE);
  589.     IF fserr <> noErr THEN
  590.       BEGIN
  591.         AlertUser(eFilterInit,fserr);
  592.         CloseResFile(resfnum);
  593.         dummy := XTNDReleaseTranslator(pChosenOne);
  594.         EXIT(ReadFile)
  595.       END;
  596.     fnum := hfsPB.ioRefNum;
  597.     importPB.RefNum := hfsPB.ioRefNum;
  598.     importPB.Directive := ImportInitAll;
  599.     XTNDCallTranslator(@importPB, gImportTranslator);
  600.  
  601.     { After completing the initialization, check for an error.  If none, proceed. }
  602.     IF importPB.result <> noErr THEN
  603.       BEGIN
  604.         AlertUser(eFilterInit,importPB.result);
  605.         CloseResFile(resfnum);
  606.         dummy := XTNDReleaseTranslator(pChosenOne);
  607.         EXIT(ReadFile)
  608.       END;
  609.  
  610.     { STAGE ONE - just read in the TEXT of the file.  Ignore pictures }
  611.  
  612.     { Set starting place to be the MAIN body of text. }
  613.     importPB.Directive := ImportInitMain;
  614.     importPB.CurrentStory := mainStory;
  615.     XTNDCallTranslator(@importPB, gImportTranslator);
  616.     IF importPB.result = noErr THEN 
  617.       BEGIN    
  618.         SetRect(tempRect, 0, 0, 0, 0);
  619.         ClipRect(tempRect);                        { close clip rect so text will not be drawn }
  620.         GetDateTime(now);
  621.         WHILE textrun < 30000 DO BEGIN
  622.             importPB.Directive := ImportGetText;
  623.             XTNDCallTranslator(@importPB, gImportTranslator);
  624.     
  625.             fserr := importPB.result;
  626.             count := importPB.TextLength;
  627.             
  628.             IF (fserr <> noErr) OR ((importPB.Directive = ImportAcknowledge) AND (count <= 0)) THEN
  629.                 LEAVE;
  630.             IF (count = 1) THEN BEGIN
  631.                 IF (ORD(Buffer[0]) < 32) THEN        { Is it a special character? }
  632.                     CASE ORD(Buffer[0]) OF
  633.                         2,    { Page Number }
  634.                         3,    { Footnote reference }
  635.                         5,    { Footnote reference }
  636.                         6,    { Merge Break Char }
  637.                         9,    { Tab }
  638.                         11,    { Column Break }
  639.                         12,    { Page Break }
  640.                         31:    { Discretionary Hyphen }
  641.                             count := 0;
  642.         
  643.                         4:    { Picture }
  644.                             { We have to dispose of the picture, even if we don't use it. }
  645.                           BEGIN
  646.                             pm := pictMiscHdl(importPB.MiscData);
  647.                             DisposHandle(Handle(pm^^.ThePicture));
  648.                             DisposHandle(Handle(pm));
  649.                             count := 0
  650.                           END;
  651.         
  652.                         21,    { Short Date }
  653.                         22,    { Abbrev Date }
  654.                         23,    { Long date }
  655.                         24,    { Abbrev + day Date }
  656.                         25:    { Long + day Date }
  657.                           BEGIN
  658.                             IF importPB.MiscData <> 0 THEN
  659.                                 IUDateString(importPB.MiscData, shortDate, theNumber)
  660.                             ELSE
  661.                                 IUDateString(now, shortDate, theNumber);
  662.                             count := ORD(theNumber[0]);
  663.                             BlockMove(Ptr(ORD4(@theNumber) + 1), @Buffer, count);
  664.                           END;
  665.                             
  666.                         26:    { Time }
  667.                           BEGIN
  668.                             IF importPB.MiscData <> 0 THEN
  669.                                 IUTimeString(importPB.MiscData, FALSE, theNumber)
  670.                             ELSE
  671.                                 IUTimeString(now, FALSE, theNumber);
  672.                             count := ORD(theNumber[0]);
  673.                             BlockMove(Ptr(ORD4(@theNumber) + 1), @Buffer, count);
  674.                           END;
  675.         
  676.                         7:    { Hard Return }
  677.                             Buffer[0] := CHR(13);
  678.                     END;
  679.                 END;
  680.     
  681.             IF count <> 0 THEN
  682.               BEGIN
  683.                 { Boy, is TextEdit buggy !  We need to see if there is enough memory to add the textrun }
  684.                 dummyptr := NewPtr(count + TESlop);
  685.                 IF dummyptr = NIL THEN
  686.                     LEAVE
  687.                 ELSE
  688.                     DisposPtr(dummyptr);
  689.     
  690.                 aPtr := IntegerPtr(@newStyle.tsFace);    { Fix a bug in text edit }
  691.                 aPtr^ := 0;
  692.     
  693.                 newStyle.tsFont := importPB.TxtFont;
  694.                 newStyle.tsFace := Style(BAND(importPB.TxtFace, QUICKDRAWSTYLES));
  695.                 newStyle.tsSize := importPB.TxtSize;
  696.                 RGBFromXTND(newStyle.tsColor, importPB.TxtColor);
  697.                 TESetStyle(doAll, newStyle, TRUE, te);
  698.     
  699.                 { Now add the number of characters to the text edit handle in this window }
  700.                 TEInsert(@Buffer, count, te);
  701.                 IF MemError <> noErr THEN
  702.                     LEAVE;
  703.     
  704.                 textrun := textrun + count;
  705.                 { NumToString(textrun, theNumber);        { Used for debugging.  Shows count in window title }
  706.                 { SetWTitle(window, theNumber); }
  707.               END;
  708.           END; {while}
  709.  
  710.             importPB.directive := importCloseMain;
  711.             XTNDCallTranslator(@importPB, gImportTranslator);
  712.         END;
  713.  
  714.         importPB.directive := importCloseAll;
  715.         XTNDCallTranslator(@importPB, gImportTranslator);
  716.  
  717.     TECalText(te);                                  { calc line starts in TERecord }
  718.     TESetSelect(textrun, textrun, te);                { Set insertion point }
  719.     AdjustScrollValues(window, TRUE);
  720.     SetRect(tempRect, -8000, -8000, 8000, 8000);
  721.     ClipRect(tempRect);                                { open clip rect so text will be drawn }
  722.  
  723.     IF resfnum <> 0 THEN
  724.         CloseResFile(resfnum);
  725.     dummy := FSClose(fnum);
  726.     dummy := XTNDReleaseTranslator(pChosenOne);
  727. END;
  728.  
  729.  
  730. (* ------------------------------------------------------------------------+------------+-------------- *)
  731. FUNCTION ReadPlainTextFile(theReply: SFReply; hTE: TEHandle): OSErr;
  732. (*    Inserts the text from the TEXT document specified by the Standard
  733. File reply record theReply into the TextEdit record specified by hTE. The
  734. file is assumed to be initially closed. The file is opened, the text is
  735. inserted at the current insertion point, the window’s scrollbars are
  736. adjusted, and the file is closed. The user is alerted if an error occured.
  737.     Note: This version of ReadPlainTextFile() is very simplistic. It reads
  738. the text into a block in the heap in one shot, then inserts it into the TE
  739. record. If the free memory isn’t at least twice the size of the text file
  740. ReadPlainTextFile() will fail. It also does not check the current size of
  741. the text of the TE record to guard against overflow. And it assumes that
  742. the specified file actually exists (which it may not if the Standard File
  743. reply record was not actually filled in by a Standard File routine). *)
  744. (*    04.19.91 m_o *)
  745. LABEL
  746.     86;
  747. VAR
  748.     window: WindowPtr;
  749.     err, dummy: OSErr;
  750.     myPB: ParamBlockRec;
  751.     hTx: Handle;
  752. BEGIN
  753.     window := FrontWindow;
  754.     SetCursor( GetCursor( watchCursor )^^ );
  755.     SetWTitle(window, theReply.fName);
  756.     hTx := NIL;
  757.     { open the text file… }
  758.     myPB.ioNamePtr := @theReply.fName;
  759.     myPB.ioVRefNum := theReply.vRefNum;
  760.     myPB.ioVersNum := 0;
  761.     myPB.ioPermssn := fsRdPerm;
  762.     myPB.ioMisc := NIL;
  763.     err := PBOpen(@myPB, FALSE);
  764.     IF err <> noErr THEN
  765.       BEGIN
  766.           AlertUser(eOpenFail,err);
  767.         ReadPlainTextFile := err;
  768.         EXIT(ReadPlainTextFile)
  769.       END;
  770.     { find out how much text in the file… }
  771.     err := PBGetEOF(@myPB, FALSE);
  772.     IF err <> noErr THEN
  773.       BEGIN
  774.           AlertUser(eOpenFail,err);
  775.         ReadPlainTextFile := err;
  776.         EXIT(ReadPlainTextFile)
  777.       END;
  778.     { get a buffer for the text… }
  779.     hTx := NewHandle(LONGINT(myPB.ioMisc));
  780.     IF hTx = NIL THEN
  781.       BEGIN
  782.           AlertUser(eCreateFail,0);
  783.         GOTO 86
  784.       END;
  785.     MoveHHi(hTx);
  786.     HLock(hTx);
  787.     { read the file into the buffer… }
  788.     myPB.ioBuffer := hTx^;
  789.     myPB.ioReqCount := LONGINT(myPB.ioMisc);
  790.     myPB.ioPosMode := fsFromStart;
  791.     myPB.ioPosOffset := 0;
  792.     IF PBRead(@myPB, FALSE) = noErr THEN
  793.       BEGIN
  794.         { insert text from buffer into TE record… }
  795.         TEInsert(hTx^, myPB.ioActCount, hTE);
  796.         { adjust window’s scrollbars… }
  797.         AdjustScrollValues(hTE^^.inPort, TRUE)
  798.       END;
  799. 86:
  800.     IF hTx <> NIL THEN
  801.         DisposHandle(hTx);
  802.     dummy := PBClose(@myPB, FALSE);
  803.     ReadPlainTextFile := err;
  804. END;
  805.  
  806. FUNCTION SetStyleFrom(oldStyle : Style): INTEGER;
  807. VAR
  808.     newStyle    : INTEGER;
  809. BEGIN
  810.     newStyle := 0;        { Plain }
  811.     
  812.     IF bold IN oldStyle THEN
  813.         newStyle := newStyle + kQDBold;
  814.         
  815.     IF italic IN oldStyle THEN
  816.         newStyle := newStyle + kQDItalic;
  817.         
  818.     IF underline IN oldStyle THEN
  819.         newStyle := newStyle + kQDUnderline;
  820.         
  821.     IF outline IN oldStyle THEN
  822.         newStyle := newStyle + kQDOutline;
  823.         
  824.     IF shadow IN oldStyle THEN
  825.         newStyle := newStyle + kQDShadow;
  826.         
  827.     SetStyleFrom := newStyle;
  828. END;
  829.  
  830. (* ------------------------------------------------------------------------+------------+-------------- *)
  831. PROCEDURE SaveFile(pChosenOne: TransDescrPtr; theReply: SFReply);
  832. TYPE
  833.     StyleRunPtr = ^StyleRun;
  834. VAR
  835.     loop        : LONGINT;
  836.     fserr, 
  837.     fnum        : INTEGER;
  838.     Match        : MatchInfo;
  839.     exportPB    : ExportParmBlock;
  840.     runlength    : LONGINT;
  841.     textbuffer    : Handle;
  842.     textface,
  843.     textsize, 
  844.     textfont, 
  845.     textjust, 
  846.     selStart, 
  847.     selEnd,
  848.     myEnd        : INTEGER;
  849.     textcolor    : SignedByte;
  850.     Paragraph    : ARRAY [1..9] OF Fixed;
  851.     tabs        : ARRAY [1..20] OF tabspec;
  852.     MinusOne    : Point    ;
  853.     tempRect    : Rect;
  854.     te            : TEHandle;
  855.     window        : WindowPtr;
  856.     start, 
  857.     stylerun    : LONGINT;
  858.     shndl        : TEStyleHandle;
  859.     dummy        : OSErr;
  860.     xerr,
  861.     vRefNum        : INTEGER;
  862.     sruns        : StyleRunPtr;
  863.     theText        : Handle;
  864.     length, 
  865.     offset,
  866.     textLength    : LONGINT;
  867.     Anentry        : STElement;
  868.     styleruns    : STPtr;
  869.     TextPtr        : Ptr;
  870.     thestyles    : STHandle;
  871. BEGIN
  872.     fserr := 0;
  873.     window := FrontWindow;
  874.      te := DocumentPeek(window)^.docTE;
  875.     { In order to save the document, we have to parse our own document, and determine
  876.       where the paragraph and style runs start and end.  This is not a simple project in
  877.       text edit! }
  878.  
  879.     { First, let's load the Translator, just so we know we can! }
  880.     xerr := XTNDLoadTranslator(pChosenOne, gExportTranslator);
  881.     IF xerr <> noErr THEN
  882.       BEGIN
  883.         AlertUser(eTranslatorLoad,xerr);
  884.         EXIT(SaveFile)
  885.       END;
  886.  
  887.     { Now, create the file so we can delete it.  (Takes care of PMSP problem) }
  888.     dummy := Create(theReply.fName, theReply.vRefNum, '????', '????');
  889.     xerr := FSDelete(theReply.fName, theReply.vRefNum);
  890.     IF xerr <> noErr THEN
  891.         { Explain we couldn't delete the file - probably a write protect error }
  892.         AlertUser(eDeleteFailed,xerr)
  893.     ELSE
  894.       BEGIN
  895.         Match := pChosenOne^.Matches[0];
  896.         fserr := Create(theReply.fName, theReply.vRefNum, Match.DocCreator, Match.DocType);
  897.         IF fserr <> noErr THEN
  898.             AlertUser(eCreateFail,fserr)
  899.         ELSE
  900.           BEGIN
  901.               fserr := FSOpen(theReply.fName, theReply.vRefNum, fnum);
  902.               IF fserr <> noErr THEN
  903.                 AlertUser(eOpenFail,fserr)
  904.           END
  905.       END;
  906.     IF fserr <> noErr THEN
  907.       BEGIN
  908.           dummy := XTNDReleaseTranslator(pChosenOne);
  909.         EXIT(SaveFile)
  910.       END;
  911.  
  912.     Paragraph[1] := 0;        { left indent offset }
  913.     Paragraph[2] := 0;        { first line indent offset }
  914.     Paragraph[3] := 0;        { right indent offset }
  915.     Paragraph[4] := 0;        { leading }
  916.     Paragraph[5] := 0;        { space before paragraph }
  917.     Paragraph[6] := 0;        { space after paragraph }
  918.     Paragraph[7] := -1;        { leading units (lines) }
  919.     Paragraph[8] := 0;        { space before units (points) }
  920.     Paragraph[9] := 0;        { space after units (points) }
  921.     FOR loop := 1 TO 20 DO
  922.         tabs[loop].TabIndent := -1;
  923.  
  924.     { Initialize the export Translator }
  925.     SetRect(tempRect, 0, 0, 0, 0);
  926.     MinusOne.v := -1;
  927.     MinusOne.h := -1;
  928.     textbuffer := NewHandle(0);
  929.     IF textbuffer = NIL THEN
  930.       BEGIN
  931.           dummy := XTNDReleaseTranslator(pChosenOne);
  932.           dummy := FSClose(fnum);
  933.         EXIT(SaveFile)
  934.       END;
  935.  
  936.     exportPB.ThePicture := NIL;
  937.     exportPB.PictRect := tempRect;
  938.     exportPB.FootnoteOffset := 0;
  939.     exportPB.PagePoint := MinusOne;
  940.     exportPB.DatePoint := MinusOne;
  941.     exportPB.TimePoint := MinusOne;
  942.  
  943.     exportPB.TextBuffer := textbuffer;
  944.     exportPB.TextLength := @runlength;
  945.     exportPB.result := @fserr;
  946.     exportPB.RefNum := @fnum;
  947.     exportPB.TxtFace := @textface;
  948.     exportPB.TxtSize := @textsize;
  949.     exportPB.TxtFont := @textfont;
  950.     exportPB.TxtColor := @textcolor;
  951.     exportPB.TxtJust := @textjust;
  952.     exportPB.ParaFmts := @Paragraph;
  953.     exportPB.Tabs := @tabs;
  954.     exportPB.FootnoteText := NIL;
  955.  
  956.     exportPB.topMargin := $00480000;        { 1 inch margin }
  957.     exportPB.bottomMargin := $00480000;        { 1 inch margin }
  958.     exportPB.leftMargin := $00480000;        { 1 inch margin }
  959.     exportPB.rightMargin := $00480000;        { 1 inch margin }
  960.     exportPB.Gutter := $000C0000;            { 12 point column gap }
  961.     exportPB.NumCols := 1;
  962.     exportPB.StartPageNum := 1;
  963.     exportPB.StartFootnoteNum := 1;
  964.     exportPB.CurrentStory := mainStory;
  965.     exportPB.RulerShowing := TRUE;
  966.     exportPB.DoubleSided := FALSE;
  967.     exportPB.TitlePage := FALSE;
  968.     exportPB.Endnotes := FALSE;
  969.     exportPB.ShowInvisibles := TRUE;
  970.     exportPB.ShowPageGuides := TRUE;
  971.     exportPB.ShowPictures := TRUE;
  972.     exportPB.AutoFootnotes := TRUE;
  973.     exportPB.SmartQuotes := TRUE;
  974.     exportPB.FractCharWidths := TRUE;
  975.     exportPB.HRes := 72;
  976.     exportPB.VRes := 72;
  977.     exportPB.WindowRect := tempRect;
  978.  
  979.     exportPB.HeaderStatus := 0;
  980.     exportPB.FooterStatus := 0;
  981.     myEnd := te^^.teLength;
  982.     exportPB.TotalCharCount := te^^.teLength;
  983.     exportPB.FootnotesExist := FALSE;
  984.  
  985.     exportPB.TheReply := theReply;
  986.     exportPB.ThisTranslator := pChosenOne^;
  987.  
  988.     selStart := te^^.selStart;
  989.     selEnd := te^^.selEnd;
  990.     SetRect(tempRect, 0, 0, 0, 0);
  991.     ClipRect(tempRect);                            { close clip rect so text will not be drawn }
  992.  
  993.     PrOpen;
  994.     IF PrError = noErr THEN BEGIN
  995.         exportPB.PrintRecord := THPrint(NewHandle(SIZEOF(TPrint)));
  996.         IF exportPB.PrintRecord <> NIL THEN BEGIN
  997.               PrintDefault(exportPB.PrintRecord);
  998.             IF PrValidate(exportPB.printRecord) THEN
  999.                 { who cares? }; 
  1000.             END;
  1001.         PrClose;
  1002.       END
  1003.     ELSE
  1004.         exportPB.PrintRecord := NIL;
  1005.  
  1006.     exportPB.Directive := ExportInitAll;
  1007.     XTNDCallTranslator(@exportPB, gExportTranslator);
  1008.  
  1009.     { OK - let's open the main story }
  1010.  
  1011.     exportPB.Directive := ExportOpenMain;
  1012.     exportPB.CurrentStory := mainStory;
  1013.     XTNDCallTranslator(@exportPB, gExportTranslator);
  1014.  
  1015.     shndl := GetStylHandle(te);        { There may not be _any_ style runs. }
  1016.     IF shndl <> NIL THEN
  1017.       BEGIN
  1018.         theText := Handle(TEGetText(te));
  1019.         textLength := te^^.teLength;
  1020.         HLock(theText);
  1021.         TextPtr := theText^;
  1022.         HLock(Handle(shndl));
  1023.         sruns := @shndl^^.runs;
  1024.         thestyles := shndl^^.styleTab;
  1025.         HLock(Handle(thestyles));
  1026.         styleruns := thestyles^;
  1027.         FOR stylerun := 0 TO shndl^^.nRuns - 1 DO
  1028.           BEGIN
  1029.             start := sruns^.startChar;
  1030.             length := StyleRunPtr(ORD4(sruns) + SIZEOF(StyleRun))^.startChar - start;
  1031.             IF length + start > textLength THEN
  1032.                 length := textLength - start;
  1033.             offset := 0;
  1034.             runlength := 0;
  1035.             { Find the associated style entry }
  1036.             Anentry := styleruns^[sruns^.styleIndex];
  1037.             IF Anentry.stSize = 0 THEN
  1038.                 Anentry.stSize := GetDefFontSize;
  1039.             textface := SetStyleFrom(Anentry.stFace);
  1040.             textsize := Anentry.stSize * 4;        { multiply by four to simulate MacWrite II font size }
  1041.             textcolor := SignedByte(RGBToXTND(Anentry.stColor));
  1042.             textfont := Anentry.stFont;
  1043.             textjust := 0;    { left; }
  1044.             WHILE offset + runlength < length DO
  1045.               BEGIN
  1046.                 WHILE offset + runlength < length DO
  1047.                   BEGIN
  1048.                     IF Ptr(ORD4(TextPtr) + runlength)^ = 13 THEN
  1049.                       BEGIN
  1050.                         runlength := runlength + 1;
  1051.                         LEAVE
  1052.                       END;
  1053.                     runlength := runlength + 1
  1054.                   END;
  1055.                 { Send runlength characters, starting at start + offset }
  1056.                 SetHandleSize(textbuffer, runlength);
  1057.                 { check to see if this fails }
  1058.                 BlockMove(TextPtr, textbuffer^, runlength);
  1059.                 exportPB.Directive := ExportWriteText;
  1060.                 XTNDCallTranslator(@exportPB, gExportTranslator);
  1061.                 TextPtr := Ptr(ORD4(TextPtr) + runlength);
  1062.                 TESetSelect(start + offset, start + offset + runlength, te);
  1063.                 offset := offset + runlength;
  1064.                 runlength := 0;
  1065.               END;
  1066.               sruns := StyleRunPtr(ORD4(sruns) + SIZEOF(StyleRun))
  1067.           END;
  1068.     
  1069.         exportPB.Directive := ExportCloseMain;
  1070.         XTNDCallTranslator(@exportPB, gExportTranslator);
  1071.       END;
  1072.  
  1073.     exportPB.Directive := ExportCloseAll;
  1074.     XTNDCallTranslator(@exportPB, gExportTranslator);
  1075.  
  1076.     IF exportPB.PrintRecord <> NIL THEN
  1077.         DisposHandle(Handle(exportPB.PrintRecord));
  1078.     dummy := FSClose(fnum);
  1079.  
  1080.     { Write resource fork now. }
  1081.     dummy := GetVol(NIL, vRefNum);
  1082.     dummy := SetVol(NIL, theReply.vRefNum);
  1083.     CreateResFile(theReply.fName);
  1084.     fnum := OpenResFile(theReply.fName);
  1085.     exportPB.Directive := ExportWriteResources;
  1086.     XTNDCallTranslator(@exportPB, gExportTranslator);
  1087.     CloseResFile(fnum);
  1088.     dummy := SetVol(NIL, vRefNum);
  1089.  
  1090.     dummy := XTNDReleaseTranslator(pChosenOne);
  1091.  
  1092.     TESetSelect(selStart, selEnd, te);            { Set insertion point }
  1093.     SetRect(tempRect, -8000, -8000, 8000, 8000);
  1094.     ClipRect(tempRect);                            { open clip rect so text will be drawn }
  1095. END;
  1096.  
  1097.  
  1098. (* ------------------------------------------------------------------------+------------+-------------- *)
  1099. FUNCTION SavePlainTextFile(fileName: Str255; vRefNum: INTEGER; dirID: LONGINT;
  1100.     hTE: TEHandle; saveAll: BOOLEAN): OSErr;
  1101. (*    Saves the text from the TextEdit record specified by hTE to the file
  1102. having the name fileName on the volume specified by vRefNum and in the
  1103. directory specified by dirID. The file is assumed to be initially closed.
  1104. It is opened, the text written out (replacing any previous contents of the
  1105. file), and the file is closed. If saveAll is TRUE the entire text of the
  1106. edit record is written out, otherwise only the text within the current
  1107. selection is saved. The user is alerted if an error occured. *)
  1108. (*    04.19.91 m_o *)
  1109. LABEL
  1110.     86;
  1111. VAR
  1112.     err, dummy: OSErr;
  1113.     mfb: SignedByte;
  1114.     myHPB: HParamBlockRec;
  1115. BEGIN
  1116.     { open the file… }
  1117.     myHPB.ioNamePtr := @fileName;
  1118.     myHPB.ioVRefNum := vRefNum;
  1119.     myHPB.ioVersNum := 0;
  1120.     myHPB.ioPermssn := fsRdWrPerm;
  1121.     myHPB.ioMisc := NIL;
  1122.     myHPB.ioDirID := dirID;
  1123.     err := PBHOpen(@myHPB, FALSE);
  1124.     IF err <> noErr THEN
  1125.       BEGIN
  1126.         AlertUser(eOpenFail,err);
  1127.         SavePlainTextFile := err;
  1128.         EXIT(SavePlainTextFile)
  1129.       END;
  1130.     { reset eof of file to zero… }
  1131.     myHPB.ioMisc := Ptr(0);
  1132.     err := PBSetEOF(ParmBlkPtr(@myHPB), FALSE);
  1133.     IF err <> noErr THEN
  1134.       BEGIN
  1135.         AlertUser(eOpenFail,err);
  1136.         GOTO 86
  1137.       END;
  1138.     { temporarily lock down text block of TE record;
  1139.       this is paranoia since PBWrite() is not supposed to move/purge memory… }
  1140.     MoveHHi(hTE^^.hText);
  1141.     mfb := HGetState(hTE^^.hText);
  1142.     HLock(hTE^^.hText);
  1143.     { write out TE text to file & reset lock-state of text block… }
  1144.     IF saveAll = TRUE THEN
  1145.       BEGIN
  1146.         myHPB.ioBuffer := hTE^^.hText^;
  1147.         myHPB.ioReqCount := hTE^^.teLength
  1148.       END
  1149.     ELSE
  1150.       BEGIN
  1151.         myHPB.ioBuffer := Ptr(ORD4(hTE^^.hText^) + hTE^^.selStart);
  1152.         myHPB.ioReqCount := hTE^^.selEnd - hTE^^.selStart
  1153.       END;
  1154.     myHPB.ioPosMode := fsFromStart;
  1155.     myHPB.ioPosOffset := 0;
  1156.     err := PBWrite(ParmBlkPtr(@myHPB), FALSE);
  1157.     HSetState(hTE^^.hText, mfb);
  1158. 86:
  1159.     dummy := PBClose(ParmBlkPtr(@myHPB), FALSE);
  1160.     SavePlainTextFile := err;
  1161. END;
  1162.  
  1163.  
  1164. (* ------------------------------------------------------------------------+------------+-------------- *)
  1165. FUNCTION SaveNewPlainTextFile(theReply: SFReply; fileType: OSType;
  1166.     hTE: TEHandle; saveAll: BOOLEAN; VAR vRefNum: INTEGER; VAR dirID: LONGINT): OSErr;
  1167. (*    Creates a new file and saves the text from the TextEdit record 
  1168. specified by hTE. The file is created with a creator of 'XTND' and filetype
  1169. fileType. The name and location of the file is specified by the Standard
  1170. File reply record *pTheReply. The directory ID and real volume reference
  1171. number of the specified location are returned through the VAR parameters
  1172. vRefNum and dDirID. Any existing file is first deleted. The file is closed
  1173. after saving its contents. If saveAll is TRUE the entire text of the edit
  1174. record is written out, otherwise only the text within the current selection
  1175. is saved. If an error occured the user is alerted and the file is deleted. *)
  1176. (*    04.19.91 m_o *)
  1177. LABEL
  1178.     86;
  1179. VAR
  1180.     err, dummy: OSErr;
  1181.     myWDPB: WDPBRec;
  1182.     myHPB: HParamBlockRec;
  1183. BEGIN
  1184.     { get the dirID and real vRefNum… }
  1185.     myWDPB.ioNamePtr := NIL;
  1186.     myWDPB.ioVRefNum := theReply.vRefNum;
  1187.     myWDPB.ioWDIndex := 0;
  1188.     myWDPB.ioWDProcID := 0;
  1189.     err := PBGetWDInfo(@myWDPB, FALSE);
  1190.     IF err <> noErr THEN
  1191.       BEGIN
  1192.         AlertUser(eCreateFail,err);
  1193.         SaveNewPlainTextFile := err;
  1194.         EXIT(SaveNewPlainTextFile)
  1195.       END;
  1196.     { delete file (if it already exists)… }
  1197.     myHPB.ioNamePtr := @theReply.fName;
  1198.     vRefNum := myWDPB.ioWDVRefNum;
  1199.     myHPB.ioVRefNum := myWDPB.ioWDVRefNum;
  1200.     myHPB.ioVersNum := 0;
  1201.     dirID := myWDPB.ioWDDirID;
  1202.     myHPB.ioDirID := myWDPB.ioWDDirID;
  1203.     err := PBHDelete(@myHPB, FALSE);
  1204.     IF (err <> noErr) & (err <> fnfErr) THEN
  1205.       BEGIN
  1206.         { …possibly locked or busy, or who knows what }
  1207.         AlertUser(eDeleteFailed,err);
  1208.         SaveNewPlainTextFile := err;
  1209.         EXIT(SaveNewPlainTextFile)
  1210.       END;
  1211.     { create the file… }
  1212.     err := PBHCreate(@myHPB, FALSE);
  1213.     IF err <> noErr THEN
  1214.       BEGIN
  1215.         AlertUser(eCreateFail,err);
  1216.         SaveNewPlainTextFile := err;
  1217.         EXIT(SaveNewPlainTextFile)
  1218.       END;
  1219.     { write text to file… }
  1220.     err := SavePlainTextFile(theReply.fName, myWDPB.ioWDVRefNum, myWDPB.ioWDDirID, hTE, saveAll);
  1221.     IF err <> noErr THEN
  1222.         GOTO 86;
  1223.     { set filetype & creator information… }
  1224.     myHPB.ioFDirIndex := 0;
  1225.     err := PBHGetFInfo(@myHPB, FALSE);
  1226.     IF err = noErr THEN
  1227.       BEGIN
  1228.         myHPB.ioDirID := myWDPB.ioWDDirID;
  1229.         myHPB.ioFlFndrInfo.fdType := fileType;
  1230.         myHPB.ioFlFndrInfo.fdCreator := 'XTND';
  1231.         err := PBHSetFInfo(@myHPB, FALSE)
  1232.       END;
  1233. 86:
  1234.     IF err <> noErr THEN
  1235.       BEGIN
  1236.         AlertUser(eCreateFail,err);
  1237.         dummy := PBHDelete(@myHPB, FALSE)
  1238.       END
  1239. END;
  1240.  
  1241.  
  1242. (* ========================================================================≠============≠============== *)
  1243. PROCEDURE DoOpen;
  1244. (*    Handler for the open command. Prompts the user for the file to open. If
  1245. the user selects a file a new document window is created and the file is
  1246. read in.
  1247.     If the XTND Library was successfully initialized its XTNDGetFile()
  1248. routine is used to get the user’s document selection, otherwise the
  1249. Standard File SFGetFile() routine is used. *)
  1250. (*    /04.19.91 m_o *)
  1251. VAR
  1252.     getIt: BOOLEAN;
  1253.     myReply: SFReply;
  1254.     myXSFPB: SFParamBlock;
  1255.     myPrompt, myBTitle: Str255;
  1256.     where: Point;
  1257.     myTypes: SFTypeList;
  1258.     numDocuments: INTEGER;
  1259.     topDoc: DocumentPeek;
  1260.     err: OSErr;
  1261. BEGIN
  1262.     IF gXTNDAvail = TRUE THEN
  1263.       BEGIN
  1264.         myXSFPB.AllowFlags := allowText;
  1265.         myXSFPB.NumStandard := kNativeTypes;
  1266.         myXSFPB.Standard := @gMyFileType;
  1267.         myXSFPB.ioResult := 0;
  1268.         myXSFPB.FileReply := @myReply;
  1269.         myXSFPB.XTNDDlogHook := NIL;        { XTNDDlgHookProcPtr(MyDlg); }
  1270.         myXSFPB.CurrentMenuItem := Load_stored;
  1271.         myXSFPB.Where.v := 0;
  1272.         myXSFPB.Where.h := 0;
  1273.         myPrompt := 'Select a file to open';
  1274.         myXSFPB.Prompt := @myPrompt;
  1275.         myBTitle := 'Open';
  1276.         myXSFPB.ButtonTitle := @myBTitle;
  1277.         myXSFPB.DialogID := 0;
  1278.         myXSFPB.SFFilterProc := NIL;
  1279.         myXSFPB.ShowAllFiles := FALSE; 
  1280.         myXSFPB.useMyTransList := FALSE;
  1281.         myXSFPB.myFileFilter := NIL;
  1282.         myXSFPB.Unused := 0;
  1283.         myReply.good := TRUE;
  1284.         getIt := XTNDGetFile(@myXSFPB);
  1285.         Load_stored := myXSFPB.CurrentMenuItem
  1286.       END
  1287.     ELSE
  1288.       BEGIN
  1289.           where.v := $40;
  1290.         where.h := $40;
  1291.         myTypes[1] := 'TEXT';
  1292.         SFGetFile(where, '', NIL, 1, myTypes, NIL, myReply);
  1293.         getIt := myReply.good
  1294.       END;
  1295.     IF getIt = TRUE THEN
  1296.       BEGIN
  1297.           numDocuments := gNumDocuments;
  1298.         DoNew;
  1299.         IF numDocuments <> gNumDocuments THEN    { Did we open a new window? }
  1300.             IF (gXTNDAvail = TRUE) & (myXSFPB.chosenTranslator > myXSFPB.NumStandard) THEN
  1301.                   ReadFile(myXSFPB.theChosenTranslator, myReply)    { Read the file in using XTND. }
  1302.             ELSE
  1303.               BEGIN
  1304.                 { Use the appropriate internally supported method of reading the file.
  1305.                   While our application claims to support three (kNativeTypes) formats, they are
  1306.                   all actually simple TEXT documents. }
  1307.                 topDoc := DocumentPeek(FrontWindow);
  1308.                 err := ReadPlainTextFile(myReply, topDoc^.docTE)
  1309.               END;
  1310.       END
  1311. END;
  1312.  
  1313.  
  1314. (* ------------------------------------------------------------------------+------------+-------------- *)
  1315. PROCEDURE DoSave(saveAs: BOOLEAN);
  1316. (*    Handler for the Save and Save As commands. The parameter saveAs
  1317. specifies the Save As command when it is TRUE.
  1318.     When handling a Save As command the user is prompted for a filename and
  1319. location to save the document. The window title of the frontmost window is
  1320. used as a default filename. If the user specifies a filename and location
  1321. the file is created (deleting any previously existing one) and the contents
  1322. of the frontmost document window are written to it.
  1323.     If the XTND Library was successfully initialized its XTNDPutFile()
  1324. routine is used to get the user’s document selection, otherwise the
  1325. Standard File SFGetFile() routine is used.
  1326.     Handling of the Save command is currently not implemented. If DoSave()
  1327. is called with saveAs FALSE it will simply beep. *)
  1328. (*    /04.19.91 m_o *)
  1329. VAR
  1330.     wTitle: Str255;
  1331.     putIt: BOOLEAN;
  1332.     myReply: SFReply;
  1333.     myXSFPB: SFParamBlock;
  1334.     window: WindowPtr;
  1335.     myPrompt, myBTitle: Str255;
  1336.     where: Point;
  1337.     vRefNum: INTEGER;
  1338.     dirID: LONGINT;
  1339.     err: OSErr;
  1340. BEGIN
  1341.     window := FrontWindow;
  1342.     GetWTitle(window, wTitle);
  1343.     IF saveAs = FALSE THEN
  1344.       BEGIN
  1345.         { Handle a simple Save routine here. }
  1346.         SysBeep(1);
  1347.         EXIT(DoSave)
  1348.       END;
  1349.     IF gXTNDAvail = TRUE THEN
  1350.       BEGIN
  1351.         myXSFPB.AllowFlags := allowText + allowExport;
  1352.         myXSFPB.NumStandard := kNativeTypes;
  1353.         myXSFPB.Standard := @gMyFileType;
  1354.         myXSFPB.ioResult := 0;
  1355.         myXSFPB.FileReply := @myReply;
  1356.         myXSFPB.ApplicNativeType := 'TEXT';
  1357.         myXSFPB.XTNDDlogHook := NIL;        { XTNDDlgHookProcPtr(MyDlg); }
  1358.         myXSFPB.CurrentSaveItem := Save_stored;
  1359.         myXSFPB.Where.v := 0;
  1360.         myXSFPB.Where.h := 0;
  1361.         myPrompt := 'Export File';
  1362.         myXSFPB.Prompt := @myPrompt;
  1363.         myBTitle := 'Save';
  1364.         myXSFPB.ButtonTitle := @myBTitle;
  1365.         myXSFPB.OrigName := @wTitle;
  1366.         myXSFPB.DialogID := 0;
  1367.         myXSFPB.SFFilterProc := NIL;
  1368.         myXSFPB.useMyTransList := FALSE;
  1369.         myXSFPB.myFileFilter := NIL;
  1370.         myXSFPB.Unused := 0;
  1371.         myReply.good := TRUE;
  1372.         putIt := XTNDPutFile(@myXSFPB);
  1373.         Save_stored := myXSFPB.CurrentSaveItem
  1374.       END
  1375.     ELSE
  1376.       BEGIN
  1377.         where.v := $40;
  1378.         where.h := $40;
  1379.         myPrompt := 'Save document as:';
  1380.         SFPutFile(where, myPrompt, wTitle, NIL, myReply);
  1381.         putIt := myReply.good
  1382.       END;
  1383.     IF putIt = TRUE THEN
  1384.         IF (gXTNDAvail = TRUE) & (myXSFPB.chosenTranslator > myXSFPB.NumStandard) THEN
  1385.             SaveFile(myXSFPB.theChosenTranslator, myReply)    { Save the file using XTND. }
  1386.         ELSE
  1387.             { Use the appropriate internally supported method of saving the file.
  1388.               While our application claims to support three (kNativeTypes) formats, they are
  1389.               all actually simple TEXT documents. The only differentiation we make is
  1390.               the fileType we create the documents as. }
  1391.             err := SaveNewPlainTextFile(myReply, 'TEXT',
  1392.                 DocumentPeek(window)^.docTE, {saveAll} TRUE, vRefNum, dirID)
  1393. END;
  1394.  
  1395.  
  1396. END.
  1397.